#include <stdio.h>
#include <stdlib.h>
#include <string.h> //refer to memset
#include <time.h>
#include <signal.h>
#include <sys/socket.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// [2012/09/05 JaxonJia add]
#define HAVE_SNPRINTF 1
#define PCAP_DONT_INCLUDE_PCAP_BPF_H
#define DLT_EN10MB  1   /* Ethernet (10Mb) */
/*
 * Structure for "pcap_compile()", "pcap_setfilter()", etc..
 */

struct bpf_program {
    u_int bf_len;
    struct bpf_insn *bf_insns;
};

#include <assert.h>
// add end

#include "pcap.h"
#include "pcap-int.h"

#define ERR_BUF_SIZE 1024

typedef unsigned short      u_int16;
typedef unsigned int        u_int32;
typedef unsigned long long  u_int64;

// [2012/09/05 JaxonJia add]
#define ETHERNET_HEADER_LEN 14
#define IP_HEADER_LEN       20
#define UDP_HEADER_LEN      8
#define PACKET_HEADER_LEN   (ETHERNET_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN)

#define TS_PT_IN_RTP        33                  // RTP中TS的payloadtype为33
#define MAX_PATH            512                 // 文件名最大长度
#define DEFAULT_PORT        6000
#define RCV_BUF_SIZE        (8 * 1024 * 1024)   // 接收socket的最大缓冲区长度
#define MAX_PACKET_SIZE     1500
#define MAX_RAND_BUF_LEN    100                 // 随机数数组的最大长度

#define ANY_PORT            ((u_int16)'*')
#define SNAP_LEN            1518                // 捕获数据的最大字节数
#define RTP_SN_OFFSET       2                   // sequence number在RTP头的偏移位置
#define RTP_SN_LEN          2                   // RTP中sequence number的长度
#define MAX_PID             32                  // pid表中的pid最大数目
#define TS_SYNC_BYTE        0x47                // TS包同步字节
#define TS_PKT_LEN          188                 // TS包长度
#define TS_FRAME_LEN        (TS_PKT_LEN * 7)    // TS流的帧长度(7个TS包)
#define TIME_STRING_LEN     30                  // 表示当前时间的字符串长度
#define MAX_OFFSET_LEN      42                  // offset的最大值
#define FILTER_EXP_LEN      100                 // 抓包时过滤字符串的最大长度

#define ONE_SECOND          1000000             // 1s = 1000ms = 1000000us

//仅抓cap包, 仅抓包保存成mpg, 仅检查丢包,
enum {DUMP2CAP = 1, DUMP2TS = 2, CHECK_LOSS = 4};

#define PCAP_FILE_MAGIC     0xa1b2c3d4          //cap文件标识,位于cap文件开头

typedef struct _capture_param
{
    u_int32         workmod;        // 指定仅抓包, 仅检查丢包, 还是抓包的同时检查丢包
    pcap_t*         handle;         // 通过 pcap_open_live 获得的设备句柄
    void*           fp_capfile;     // 通过pcap_dump_open打开的cap文件句柄或fopen打开的mpg文件句柄
    FILE*           fp_logfile;     // 发现丢包时记录丢包的log文件句柄
    u_int32         offset;         // 数据部分的偏移位置(RTP头长度)
    int             last_rtp_sn;    // 上一个包的RTP SN
    struct timeval  cap_begin;      // 抓包开始的时间
    u_int32         minute;         // 抓包定时时间，单位：分钟
    u_int32         is_first_run;   // 首次运行标识
}CAPTURE_PARAM;

// 将cap文件数据发往指定组播地址和端口
int  udp_replay(const char* filename, const char* ip, u_int16 port, u_int32 offset = 0);
void sighander(int sig);
int  print_usage(char* program_name);
// [2012/09/05 JaxonJia add]
// 将cap包转换成ts文件
int  cap_convert(const char* input_file, const char* output_file, u_int32 workmod = 0,
               const char* loss_logfile = NULL, u_int32 offset = 0);
// 检查RTP的连续性
int check_rtp_sn(const u_char *rtpdata, int &last_rtp_sn, FILE* logfile, int cap_pkt_idx=-1);
// 检查TS流的连续性
int  check_ts_continuity_counter(const u_char *tsdata, int tslen, FILE* logfile, int cap_pkt_idx=-1);
// pcap包捕获功能初始化
int init_capture(const char* filter_string, const char* dev, pcap_t* &cap_handle);
// pcap_loop的回调函数, 对捕获到的数据包进行处理(转存、分析丢包)
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
// 捕获指定组播地址和端口的TS流, 调用got_packet进行相关处理
int  capture(const char* ip, u_int16 port, const char* outfile, u_int32 workmod = 0,
            const char* logfile = NULL, const char* dev = NULL, u_int32 offset = 0, u_int32 minute = 0);
// 检查cap文件或ts文件是否存在RTP丢包和ts丢包
int  check_offline_file(const char* filename, const char* logfile, u_int32 offset = 0);
// 当前时间与开始时间的时间间隔超出指定时间就返回true
bool time_interval(struct timeval &ts_begin, u_int32 us);
// 获取日志时间字符串函数,用于日志信息打印时
void get_time_str(char *time_str);
// 获取指定组播地址和端口的源IP地址
int print_ip(const char* ip, u_int16 port, const char* dev = NULL);
// 组播转单播
int udp_transfer(char* srcip, u_int16 srcport, char* dstip, u_int16 dstport, int offset = 0, const char* dev=NULL);
// add end

// 从cap包数据中提取来源IP和端口, 返回点分十进制的IP:Port字符串在静态内存中的指针
char* get_src_ip_port(const unsigned char *pkt_data, char* ip=NULL, u_int16* port=NULL);
// 是否为应随机丢掉的数据包
bool is_loss_pkt(u_int16 rate = 0);

//common interface for create socket
in_addr_t get_addr_by_interface(const char* interface);
int  sock_recv(int &sock, const char* ip, u_int16 port, char* errbuf, const char *dev=NULL);
int  sock_send(int &sock, char* errbuf);

//ts1-ts2
long gettsgap(struct timeval ts1, struct timeval ts2);
//ts = ts1 -ts2
int  gettsgap(struct timeval ts1, struct timeval ts2, struct timeval *ts);
// 扩展pcap_open_live接口，增加bufsize设置
pcap_t *pcap_open_live_ex(const char *source, int snaplen, int promisc, int to_ms, char *errbuf, int bufsize=RCV_BUF_SIZE);
int string_ends_with(const char *str, const char *suffix);
//是否组播地址
bool is_multicast_ip(const char *ip);

#ifndef MSVERSION
#define MSVERSION   __DATE__
#endif

// 错误返回值
#define ERROR_SOCK_CREAT        -1
#define ERROR_SOCK_SET_OPT      -2
#define ERROR_SOCK_BINDING      -3
#define ERROR_SOCK_SEND         -4
#define ERROR_SOCK_SELECT       -5

#define ERROR_OPEN_FILE         -6
#define ERROR_READ_FILE         -7
#define ERROR_WRITE_FILE        -8

#define ERROR_CAPTURE           -9
#define ERROR_INVALID_PKT       -10

#define PCAP_ERROR_DEVICE       -11
#define PCAP_ERROR_COMPILE      -12
#define PCAP_ERROR_SETFILTER    -13

#define ERROR_INVALID_PARAM     -14

#define MAX_RETRY_TIMES         5
#define MAX_IP_LEN              20
#define MAX_PORT_LEN            10

#define OK                      0

